<?php
/**
 * @link https://ym2.cleverstone.top
 * @copyright Copyright (c) 2020 Yii Manager Software LLC
 */

namespace builder\helper;

/**
 * 数学
 * @author cleverstone
 * @since ym2.0
 */
class Math
{
    /**
     * 高精度加法
     * @param mixed ...$params
     * @return float
     * @see bcadd()
     * @since >= php5.6
     */
    public static function add(...$params)
    {
        // 参数数量>=1
        if (count($params) == 0) {
            throw new \InvalidArgumentException('Missing Parameters.');
        }

        $tempAddend = 0;
        foreach ($params as $addend) {
            $tempAddend = bcadd($addend, $tempAddend, 5);
        }

        return (float)$tempAddend;
    }

    /**
     * 高精度减法
     * @param mixed ...$params
     * @return float
     * @see bcsub()
     * @since >= php5.6
     */
    public static function sub(...$params)
    {
        // 参数数量>=1
        if (count($params) == 0) {
            throw new \InvalidArgumentException('Missing Parameters.');
        }

        // 拿出第一个参数,做为被减数
        $minuend = array_shift($params);
        // 剩余数量为空,则直接返回被减数
        if (!count($params)) {
            return $minuend;
        }

        // 剩余减数累加
        $total = self::add(...$params);
        // 做精度减法运算,得出结果
        return (float)bcsub($minuend, $total, 5);
    }

    /**
     * 高精度乘法
     * @param mixed ...$params
     * @return float
     * @see bcmul()
     * @since >= php5.6
     */
    public static function mul(...$params)
    {
        // 参数数量>=1
        if (count($params) == 0) {
            throw new \InvalidArgumentException('Missing Parameters.');
        }

        $tempMultiplier = 1;
        foreach ($params as $multiplier) {
            $tempMultiplier = bcmul($multiplier, $tempMultiplier, 5);
        }

        return (float)$tempMultiplier;
    }

    /**
     * 高精度除法
     * @param mixed ...$params
     * @return float
     * @see bcdiv()
     * @since >= php5.6
     */
    public static function div(...$params)
    {
        // 参数数量>=1
        if (count($params) == 0) {
            throw new \InvalidArgumentException('Missing Parameters.');
        }

        // 拿出第一个参数,做为被除数
        $dividend = array_shift($params);
        // 剩余数量为空,则直接返回被除数
        if (!count($params)) {
            return $dividend;
        }

        // 剩余除数累乘
        $total = self::mul(...$params);
        // 做精度除法运算,得出结果
        return (float)bcdiv($dividend, $total, 5);
    }

    /**
     * 向下保留n位
     * @param float|int $val 值
     * @param int $precision 精度，默认：2
     * @return float
     */
    public static function floor($val, $precision = 2)
    {
        return bcadd($val, 0, $precision);
    }

    /**
     * 向上保留n位
     * @param float|int $val 值
     * @param int $precision 精度，默认：2
     * @return float
     */
    public static function ceil($val, $precision = 2)
    {
        if ($precision < 0) {
            throw new \InvalidArgumentException('The parameter [[precision]] must be greater than 0.');
        }

        $multiplier = pow(10, $precision);
        $result = bcdiv(ceil(self::mul($val, $multiplier)), $multiplier, $precision);

        return $result;
    }

    /**
     * 四舍五入保留n位
     * @param float|int $val 值
     * @param int $precision 精度，默认：2
     * @return float
     */
    public static function round($val, $precision = 2)
    {
        return round($val, $precision);
    }
}